/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package researchgrants.parts.GrantRequest.agency;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.SortedMap;
import researchgrants.parts.LoggedData.panels.*;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.ActionListener;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import researchgrants.parts.LoggedData.LoggedData;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import researchgrants.parts.LoggedData.panels.lists.LoggedDataPanelsList;
import researchgrants.parts.db.Db;

/**
 * A set of panels to view and edit AgencyContact from within a GrantRequestView
 * @author DOStudent1
 */
public class LoggedDataPanelsAgencyContact extends LoggedDataPanels  {

    // an internal data initialization test
    private void checkInitializedData() {
        if (!isParentInitialized()) {
            throw new RuntimeException("Didn't set parent");
        }
    }
    
    private JPanel pnlViewContent;
    
    // re/create the view content - upon adding or changing some inner element, excluding direct fields
    private void createView() {
        pnlViewContent.removeAll();
        String data=super.getData().value();
        if (!data.equals("")) {
            // if saved a value
            
            // the resulting objects from the saved value
            AgencyContact agencyContact=AgencyContact.getById(Integer.parseInt(data));
            Agency agency=agencyContact.getCurrentAgency();
            AgencyCategory agencyCategory=agency.getCurrentAgencyCategory();
            
            // Displays the Agency
            JPanel pnlContentAgency=new JPanel(new FlowLayout(FlowLayout.LEFT, 2,0));
            pnlContentAgency.add(new JLabel("Agency: "));
            pnlContentAgency.add(new JLabel(agency.getCurrentAgencyName()));
            JButton btnAgency=new JButton("View");
            btnAgency.addActionListener(new AgencyViewActionListener(agency, getParentWindow()));
            pnlContentAgency.add(btnAgency);
            pnlViewContent.add(pnlContentAgency, BorderLayout.NORTH);

            // Displays the AgencyCategory
            JPanel pnlContentAgencyCategory=new JPanel(new FlowLayout(FlowLayout.LEFT, 2,0));
            pnlContentAgencyCategory.add(new JLabel("Agency Category: "));
            pnlContentAgencyCategory.add(new JLabel(agencyCategory.getDescription()));
            pnlViewContent.add(pnlContentAgencyCategory, BorderLayout.CENTER);
            
            // Displays the AgencyContact
            JPanel pnlContentAgencyContact=new JPanel(new FlowLayout(FlowLayout.LEFT, 2,0));
            pnlContentAgencyContact.add(new JLabel("Contact: "));
            pnlContentAgencyContact.add(new JLabel(agencyContact.getDescription()));
            JButton btnAgencyContact=new JButton("View");
            btnAgencyContact.addActionListener(new AgencyContactViewActionListener(agencyContact, getParentWindow()));
            pnlContentAgencyContact.add(btnAgencyContact);
            pnlViewContent.add(pnlContentAgencyContact, BorderLayout.SOUTH);
        }
        pnlViewContent.revalidate();
        getParentWindow().pack();
    }

    // Returns the View panel
    @Override
    public Component getViewComponent() {
        checkInitializedData();
        pnlViewContent=new JPanel(new BorderLayout(0, 0));
        createView();
        return(pnlViewContent);
    }

    
    private JPanel pnlAgencies;
    private JPanel pnlContacts;
    private JPanel pnlEditContent;

    private LoggedDataPanelsList agenciesPanels;
    private LoggedDataPanelsList contactPanels;
    
    // Returns the Edit panel
    @Override
    public Component getEditComponent() {
        pnlEditContent=new JPanel(new BorderLayout(0, 0));

        pnlAgencies=new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
        pnlContacts=new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));

        // First part to choose - Agency
        pnlEditContent.add(pnlAgencies, BorderLayout.NORTH);
        // Second part to choose - Contact within the selected Agency
        pnlEditContent.add(pnlContacts, BorderLayout.SOUTH);
        
        createAgencyList(null);

        return(pnlEditContent);
    }
    
    // re/create the agencies list
    // if given a selectedAgency, it will be selected
    private void createAgencyList(Integer selectedAgency) {
        pnlAgencies.removeAll();

        pnlAgencies.add(new JLabel("Agency:"));
        
        // create the Panels to choose the Agency from
        agenciesPanels=new LoggedDataPanelsListAgencies();

        // Because these are just panels and they are not associated with a PanelsManager, We need to listen to changes in it
        agenciesPanels.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                // if selection is changed, call agencyChanged for further input requests
                agencyChanged(null);
            }

        });

        pnlAgencies.add(agenciesPanels.getEditComponent());

        JButton btnAddAgency=new JButton("Add Agency");
        btnAddAgency.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                inputNewAgency();
            }

        });
        pnlAgencies.add(btnAddAgency);
        
        // populate the initial data, if applicable
        if (selectedAgency!=null) {
            agenciesPanels.setSelected(selectedAgency);
        } else {
            if (super.getData()!=null) {
                String data=super.getData().value();
                if (!data.equals("")) {
                    AgencyContact agencyContact=AgencyContact.getById(Integer.parseInt(data));
                    Agency agency=agencyContact.getCurrentAgency();
                    agenciesPanels.setSelected(agency.getId());
                }
            } 
        }
        // updates listeners of a change
        notifyCurrentStatus();
        
        pnlAgencies.revalidate();
        getParentWindow().pack();
        
        //TODO: When adding a new angecy, doesn't validates correctly the contacts
    }
    

    // Agency selected, populate AgencyContacts of the selected Agency
    // the selectedAgencyContactId is optional. If given, this contact will be selected by default
    private void agencyChanged(Integer selectedAgencyContactId) {
        pnlContacts.removeAll();
        if (agenciesPanels.isEmpty()) {
            // if no Angecy is selected, doesn't display anything and flags this using the following assignment.
            contactPanels=null;
        } else {
            // Gets the selected Agency
            int selectedAgencyId=Integer.parseInt(agenciesPanels.getEdittedValue());
            // Creates the list of all AgencyContacts for the selected Agency
            contactPanels=new AgencyContactLoggedDataPanelsList(selectedAgencyId);

            // if something was requested to be selected, do that.
            // if not, see if a saved value exists, and select it.
            if (selectedAgencyContactId!=null) {
                contactPanels.setSelected(selectedAgencyContactId);
            } else {
                // populate the initial data, if applicable
                if (super.getData()!=null) {
                    String data=super.getData().value();
                    if (!data.equals("")) {
                        AgencyContact agencyContact=AgencyContact.getById(Integer.parseInt(data));
                        contactPanels.setSelected(agencyContact.getId());
                    }
                }
            }
            // Again, because we have just Panels and not a Manager, listen to events
            contactPanels.addChangeListener(new ChangeListener() {
                public void stateChanged(ChangeEvent e) {
                    // calls contactChanged upon a selection change to the list
                    contactChanged();
                }
            });

            pnlContacts.add(new JLabel("Contact:"));
            pnlContacts.add(contactPanels.getEditComponent());
            
            JButton btnAddContact=new JButton("Add Contact to Agency");
            btnAddContact.addActionListener(new AddAgencyContactActionListener(selectedAgencyId));
            pnlContacts.add(btnAddContact);
        }
        notifyCurrentStatus();
        pnlContacts.revalidate();
        getParentWindow().pack();
    }
    
    // signals to listeners, including a possible Manger, that there is a change with the content
    private void contactChanged() {
        notifyCurrentStatus();
    }


    // called when the user request to add a new agency
    private void inputNewAgency() {
        Agency newAgency = Agency.inputNew(getParentWindow());
        if (newAgency!=null) {
            // recreates the list of Agencies, with the newly inserted Angecy selected
            createAgencyList(newAgency.getId());
        }
    }

    // called when the user selects an Agency and request to add a new AgencyContact to it
    private void inputNewAgencyContact(int selectedAgencyId) {
        AgencyContact newAgencyContact = AgencyContact.inputNew(getParentWindow(), selectedAgencyId);
        // if the user added a new contact, choose it
        if (newAgencyContact!=null) {
            // recreates the AgencyContactsList, with the newly created AgencyContact selected
            agencyChanged(newAgencyContact.getId());
        }
    }

    // Returns the value of the current selection
    @Override
    public String getEdittedValue() {
        // If no AgencyContact is selected, returns an empty (null) value
        if (contactPanels==null) {
            return("");
        } else {
            // an AgencyContact is selected, returns its value
            return(contactPanels.getEdittedValue());
        }
    }

    // Empty only if no agency is selected
    @Override
    public boolean isEmpty() {
        return(agenciesPanels.isEmpty());
    }
    
    // Valid if no agency is selected (yet the value is empty), or agency and contact are selected
    @Override
    public boolean isValid() {
        return(agenciesPanels.isEmpty() || (contactPanels!=null && (!contactPanels.isEmpty())));
    }
    
    // Displays an AgencyContact in a seperate window
    private class AgencyContactViewActionListener implements ActionListener {
        AgencyContact agencyContact;
        Window parent;
    
        private AgencyContactViewActionListener(AgencyContact agencyContact, Window parent) {
            this.agencyContact=agencyContact;
            this.parent=parent;
        }

        public void actionPerformed(ActionEvent e) {
            agencyContact.show(parent);
            // redisplay the content, if changed through the window
            createView();
        }
    }

    // Displays an Agency in a seperate window
    private class AgencyViewActionListener implements ActionListener {
        Agency agency;
        Window parent;
    
        private AgencyViewActionListener(Agency agency, Window parent) {
            this.agency=agency;
            this.parent=parent;
        }

        public void actionPerformed(ActionEvent e) {
            agency.show(parent);
            // redisplay the content, if changed through the window
            createView();
        }
    }
    
    
    // Maintain a list of AgencyContacts for the given agencyId
    private static class AgencyContactLoggedDataPanelsList extends LoggedDataPanelsList {

        private int agencyId;
        public AgencyContactLoggedDataPanelsList(int agencyId) {
            super();
            this.agencyId=agencyId;
        }

        public SortedMap<String, String> getListMap() {
            SortedMap<String, String> agencyContacts = new TreeMap<String, String>();
            SortedMap<String, String> agencyContactsInner = null;
            try {
                Connection conn = Db.openDbConnection();
                // queries the specific Agency
                PreparedStatement prepareStatement = Db.createPreparedStatement(conn, "SELECT ContactID, NameRef FROM tblAgencyContacts WHERE AgencyID=?");
                prepareStatement.setInt(1, agencyId);
                ResultSet agencyContactsResultSet = prepareStatement.executeQuery();
                // creates a map list of all agencyContact
                agencyContactsInner = Db.getMap(agencyContactsResultSet);
                agencyContactsResultSet.close();
                prepareStatement.close();
                Db.closeDbConnection(conn);
            } catch (SQLException ex) {
                Logger.getLogger(LoggedDataPanelsAgencyContact.class.getName()).log(Level.SEVERE, null, ex);
            }

            Set<String> keys = agencyContactsInner.keySet();
            for (Iterator<String> it = keys.iterator(); it.hasNext();) {
                String key = it.next();
                LoggedData ContactName = LoggedData.getByID(Integer.parseInt(agencyContactsInner.get(key)));
                agencyContacts.put(key, ContactName.value());
            }
            return agencyContacts;
        }
    }

    // if no agencies are selected, the component is valid though empty
    // if an agency is selected, but no contact is selected, the component is invalid
    // if both agency and contact are selected, the component is valid and has a value
    private void notifyCurrentStatus() {
        notifyAllChangeListeners(new ChangeEvent(this));
    }

    // creates a new AgencyContact that will belong to the given selectedAgencyId
    private class AddAgencyContactActionListener implements ActionListener {

        private final int selectedAgencyId;

        public AddAgencyContactActionListener(int selectedAgencyId) {
            this.selectedAgencyId = selectedAgencyId;
        }

        public void actionPerformed(ActionEvent e) {
            inputNewAgencyContact(selectedAgencyId);
        }
    }

    // Maintain a list of all Agencies
    private static class LoggedDataPanelsListAgencies extends LoggedDataPanelsList {

        public LoggedDataPanelsListAgencies() {
        }

        public SortedMap<String, String> getListMap() {
            SortedMap<String, String> agencies = new TreeMap<String, String>();
            SortedMap<String, String> agenciesInner = null;
            try {
                Connection conn = Db.openDbConnection();
                PreparedStatement prepareStatement = Db.createPreparedStatement(conn, "SELECT AgencyID, AgencyNameRef FROM tblAgencies");
                ResultSet agenciesResultSet = prepareStatement.executeQuery();
                agenciesInner = Db.getMap(agenciesResultSet);
                agenciesResultSet.close();
                prepareStatement.close();
                Db.closeDbConnection(conn);
            } catch (SQLException ex) {
                Logger.getLogger(LoggedDataPanelsAgencyContact.class.getName()).log(Level.SEVERE, null, ex);
            }

            Set<String> keys = agenciesInner.keySet();
            for (Iterator<String> it = keys.iterator(); it.hasNext();) {
                String key = it.next();
                LoggedData agencyName = LoggedData.getByID(Integer.parseInt(agenciesInner.get(key)));
                agencies.put(key, agencyName.value());
            }
            return agencies;
        }
    }
}
